闲话 20.9.20
闲话
吓死我了我还以为joke3579的闲话永久停更了。
不知道为什么 最近这些天一直在唱《non-breath oblige》
但是没有歌词 因此很抓狂 因为原曲很快我根本记不住词
哪位好心人给一下歌词(
话说饭最近似乎停更了
然后转职成了职业画家(
这是一张画!
好看!
话说他歌的pv都是他(以及勤奋的助手们)画的
饭还在发布《若能化作彗星》后拿这首歌的pv做例子讲了一下呢
事职业画家!
有哪位好心人能和我说一下饭的近况啊(
有新歌吗(多半没有吧我猜)
有那更好了
孩子瘾犯了
一道dp题(?)
给一棵 个点的 AVL树,节点权值即为编号。需要把它删到剩下 个点。构造一种方案使得删完后的树还是 AVL 树且字典序最小。输出每个点在该方案下的存留情况。
。
这题有 的做法但我不会。讲一下 的。
首先贪一下,按照先序遍历枚举节点通过dp查看可达性。
具体地,设 为在原树形态的基础上以 为根节点,构成一棵深度为 的 AVL 需要几个节点。容易写出dp方程:
枚举节点,将该节点与其所有祖先标记为必选,标记过程中更新标记对象父节点的dp数组。随后对根节点进行判断。如果在钦定该节点必选的情况下存在一种深度 使得 ,该节点就可以被选择。
因此有标记 节点为必选的方式:赋 为 。
若不可被选择,需要返回未选的情况。
对单个节点的判断是 的。由于是 AVL 树,因此树高为 。
code
#include <bits/stdc++.h>
#define rep(i,a,b) for (register int (i) = (a); (i) <= (b); ++(i))
#define pre(i,a,b) for (register int (i) = (a); (i) >= (b); --(i))
using namespace std;
#define int long long
const int N = 5e5 + 10;
int n, k, t1, rt, u, ans, flag[N], f[N][25], g[N][25];
#ifdef ONLINE_JUDGE
char buf[1<<21], *p1 = buf, *p2 = buf; inline char getc() { return (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1<<21, stdin), p1 == p2) ? EOF : *p1++); }
#define getchar getc
#endif
template <typename T> inline void get(T & x){
x = 0; char ch = getchar(); bool f = false; while (ch < '0' or ch > '9') f = f or ch == '-', ch = getchar();
while (ch >= '0' and ch <= '9') x = (x<<1) + (x<<3) + (ch^48), ch = getchar(); f && (x = -x);
} template <typename T, typename ... Args> inline void get(T & x, Args & ... _Args) { get(x); get(_Args...); }
struct node {
int fa, ls, rs, dp, cnt;
#define ls(p) avl[p].ls
#define rs(p) avl[p].rs
#define fa(p) avl[p].fa
#define dep(p) avl[p].dp
#define cnt(p) avl[p].cnt
#define isls(p) (p == ls(fa(p)))
} avl[N];
void upd(int u) {
f[u][0] = f[u][1] = 1e9;
for (int i = 2; i <= dep(u); i++) f[u][i] = min( f[ls(u)][i - 1] + min( f[rs(u)][i - 1] , f[rs(u)][i - 2] ) + 1 , f[ls(u)][i - 2] + f[rs(u)][i - 1] + 1 );
}
void dfs(int u) {
if (ls(u)) dfs(ls(u));
if (rs(u)) dfs(rs(u));
dep(u) = max(dep(ls(u)), dep(rs(u))) + 1;
upd(u);
f[u][0] = 0, f[u][1] = 1;
}
bool check(int u) {
if (flag[u]) return 1;
flag[u] ++;
for (int i = 0; i <= dep(u); i++) g[u][i] = f[u][i];
f[u][0] = 1e9;
while (u != rt) {
u = fa(u);
for (int i = 0; i <= dep(u); i++) g[u][i] = f[u][i];
upd(u); flag[u] ++;
} int mn = 1e9;
for (int i = 1; i <= dep(rt); i++) mn = min(mn, f[rt][i]);
return mn <= k;
}
void roll_back(int u) {
flag[u] --;
for (int i = 0; i <= dep(u); i++) f[u][i] = g[u][i];
while (u != rt) {
u = fa(u);
for (int i = 0; i <= dep(u); i++) f[u][i] = g[u][i];
flag[u] --;
}
}
signed main() {
get(n, k);
rep(i,1,n) {
get(t1);
if (t1 == -1) rt = i;
else {
if (t1 > i) ls(t1) = i;
else rs(t1) = i;
} fa(i) = t1;
} memset(f, 0x3f, sizeof f);
rep(i,0,n) f[i][0] = 0;
dfs(rt);
rep(i,1,n) {
if (check(i)) cout << 1;
else cout << 0, roll_back(i);
}
return 0;
}
置换环
定义在集合 上的置换为一个 的双射 。容易发现,任何一个置换 都可以被大小为 的排列 表示。由置换的定义自然导出单位置换 与置换的复合运算。定义 为 自复合 次后得到的置换。对于置换 ,若 且 极小,就称 是 的周期。
对于一个 上的置换 对应的排列 ,我们在一个 个点的图上,由 向 连边,会得到一个由环构成的有向图,这称作 的置换环图,其中的环称作 的一个置换环。
断言: 的周期为所有置换环大小的最小公倍数。
证明:
当 仅有一个置换环时定理显然成立,因为每个节点都需要环大小长度的遍历后才能回到其本身。
首先考察 仅有两个置换环的情况。设这两个环的大小为 与 。当 时退化到一个置换环的情况,显然成立。因此考虑 。不妨设 。
我们需要的是同时遍历完两个环的最小长度。现讨论遍历两个环的过程中位置的同步度。不妨设遍历 次 环后 环被遍历完。容易发现定义是良的,因为当 时显然成立。
考虑当遍历完一个环后在另一个环上余下的长度 。
若 ,那 。因此有
考虑 。由于现在需要让 与 同步,因此我们现在需要解决的子问题表述出了 。根据更相减损术,这表明 。这也表示了 是当前情况的特解。
因此当只存在两个环时有
同时这给出了将两个大小任意的环归约成一个等价环的方法。
对于 个环的情况,可以先将两个环归约为一个环,这就转化到了 个环的情况。根据数学归纳法,该断言成立。
以下是博客签名,与正文无关。
请按如下方式引用此页:
本文作者 joke3579,原文链接:https://www.cnblogs.com/joke3579/p/chitchat220920.html。
遵循 CC BY-NC-SA 4.0 协议。
请读者尽量不要在评论区发布与博客内文完全无关的评论,视情况可能删除。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)